#ifndef UTILITY_CAST_H
#define UTILITY_CAST_H

#include "type.h"

namespace Cast {

template<typename LHS, typename RHS> constexpr LHS PADD(LHS p, RHS dp) {
    STATIC_ASSERT_INTEGRAL(RHS);
    return p + static_cast<std::ptrdiff_t>(dp);
}

template<typename LHS, typename RHS> inline LHS &assign(LHS &lhs, RHS &rhs) {
    return lhs = static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &iadd(LHS &lhs, RHS &rhs) {
    return lhs += static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &isub(LHS &lhs, RHS &rhs) {
    return lhs -= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &imul(LHS &lhs, RHS &rhs) {
    return lhs *= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &idiv(LHS &lhs, RHS &rhs) {
    return lhs /= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &imod(LHS &lhs, RHS &rhs) {
    return lhs %= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &iand(LHS &lhs, RHS &rhs) {
    return lhs &= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &ior(LHS &lhs, RHS &rhs) {
    return lhs |= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &ixor(LHS &lhs, RHS &rhs) {
    return lhs ^= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &ilshift(LHS &lhs, RHS &rhs) {
    return lhs <<= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> inline LHS &irshift(LHS &lhs, RHS &rhs) {
    return lhs >>= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr LHS ADD(LHS lhs, RHS rhs) {
    return lhs + static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr LHS SUB(LHS lhs, RHS rhs) {
    return lhs - static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr LHS MUL(LHS lhs, RHS rhs) {
    return lhs * static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr LHS DIV(LHS lhs, RHS rhs) {
    return lhs / static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr LHS MOD(LHS lhs, RHS rhs) {
    return lhs % static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr LHS BAND(LHS lhs, RHS rhs) {
    return static_cast<LHS>(lhs & static_cast<LHS>(rhs));
}

template<typename LHS, typename RHS> constexpr LHS BOR(LHS lhs, RHS rhs) {
    return static_cast<LHS>(lhs | static_cast<LHS>(rhs));
}

template<typename LHS, typename RHS> constexpr LHS BXOR(LHS lhs, RHS rhs) {
    return static_cast<LHS>(lhs ^ static_cast<LHS>(rhs));
}

template<typename LHS, typename RHS> constexpr LHS LSHIF(LHS lhs, RHS rhs) {
    return static_cast<LHS>(lhs << static_cast<LHS>(rhs));
}

template<typename LHS, typename RHS> constexpr LHS RSHIFT(LHS lhs, RHS rhs) {
    return static_cast<LHS>(lhs >> static_cast<LHS>(rhs));
}

template<typename LHS, typename RHS> constexpr bool EQ(const LHS &lhs, const RHS &rhs) {
    return lhs == static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr bool NE(const LHS &lhs, const RHS &rhs) {
    return lhs != static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr bool LT(const LHS &lhs, const RHS &rhs) {
    return lhs < static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr bool GT(const LHS &lhs, const RHS &rhs) {
    return lhs > static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr bool LE(const LHS &lhs, const RHS &rhs) {
    return lhs <= static_cast<LHS>(rhs);
}

template<typename LHS, typename RHS> constexpr bool GE(const LHS &lhs, const RHS &rhs) {
    return lhs >= static_cast<LHS>(rhs);
}

}

#endif